/* d_ca.c
*	Client user program of distributed Coach Attendant in a train simulation
*	
*	Simulates a Coach Attendant
*/
 
#include "syscall.h"

const int NUMBER_OF_COACHATTENDANTS = 3; /*How many Coach Attendant on the Train*/
const int MAXPASSENGERS = 30; /*Maximum Passengers*/

/* Lock */
int waitingForAttendantsLock;
int coachAttendantLineLock[3];
int signalPortersLock;
int signalAttendantsLock;

/* CV */
int coachAttendantLine[3];
int coachAttendantAvailable[3];
int waitingForAttendants;
int signalPorters;
int signalAttendants;

/* MV */
int waitingToBeSatLineLength[3];
int coachAttendantBusy[3];
int g_seatingPsgNumber[3];
int seatAssignment[3];
int firstClass[40]; 
int numNeedHelpWithLuggage;
int g_caIndex;
int attendantBroadcast;
int passengerWaitingToBeSeated;
int seats[120];/* true if seat is occupied 40*3*/
int numFirstClassThatBoarded;

void Coach_Attendant(void);
void Dummy(void);
void setupMonitors(void);
void itoa(char arr[], int size, int val);

int main(int argc, char **argv)
{
	void (*myCA)(void);
	void (*myDummy)(void); /*For some reason if you fork just once, nothing works*/
	
	myCA = &Coach_Attendant;
	myDummy = &Dummy;
	
	setupMonitors(); /*Requesting all the locks, CVs, and MVs needed by Ticket Checker client*/
	Fork(myCA);
	Fork(myDummy);

	Exit(0);
}

void Dummy()
{
	PrintOut("Dummy Thread\n", 13);
    Exit(0);		
}

void setupMonitors(){
	int i;
	char indexBuf[2];
	char nameBuf[4]; /*a prefix will be put in first two slots, then the local index*/
	
	for (i = 0; i < MAXPASSENGERS; i ++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'f';
		nameBuf[1] = 'c';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "fc6"*/
		firstClass[i] = CreateMV(nameBuf, 4, 1);
	}
	
	for(i=0; i<3*MAXPASSENGERS; i++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 's';
		nameBuf[1] = 't';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "st2"*/
		seats[i] = CreateMV(nameBuf, 4, 1);
	}
	
	for (i = 0; i < NUMBER_OF_COACHATTENDANTS; i ++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'c';
		nameBuf[1] = 'a';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "ca2"*/
		
		coachAttendantLineLock[i] = CreateLock(nameBuf, 4, 1);
		
		coachAttendantLine[i] = CreateCV(nameBuf, 4, 1);
		nameBuf[0] = 'c';
		nameBuf[1] = 'v'; /* CA aValiable */
		coachAttendantAvailable[i] =CreateCV(nameBuf, 4, 1);
		
		waitingToBeSatLineLength[i] = CreateMV(nameBuf, 4, 1);
		nameBuf[0] = 'c';
		nameBuf[1] = 'b'; /* CA Busy */
		coachAttendantBusy[i] = CreateMV(nameBuf, 4, 1);
		nameBuf[0] = 's';
		nameBuf[1] = 'n'; /* Seat Number */
		g_seatingPsgNumber[i] = CreateMV(nameBuf, 4, 1);
		nameBuf[0] = 's';
		nameBuf[1] = 'a'; /* Seat Assignment */
		seatAssignment[i] = CreateMV(nameBuf, 4, 1);
	}
	
	waitingForAttendantsLock = CreateLock("waitingForAttenLock", 19, 1);
	signalPortersLock = CreateLock("signalPtsLock", 13, 1);
	signalAttendantsLock = CreateLock ("signalAttenLock", 15, 1);

	waitingForAttendants = CreateCV("waitingForAttendants", 20, 1);
	signalPorters = CreateCV("signalPorters", 13, 1);
	signalAttendants = CreateCV ("signalAttendants", 16, 1);
	
	g_caIndex = CreateMV("g_caIndex", 9, 1);
	numNeedHelpWithLuggage = CreateMV("numNeedHelpWithLug", 18, 1);
	attendantBroadcast = CreateMV("attBroadcastMV", 14, 1);
	passengerWaitingToBeSeated = CreateMV("psgWaitToBeSeated", 17, 1);
	numFirstClassThatBoarded = CreateMV("nFClassThatBoarded", 18, 1);
}

void Coach_Attendant(){
	int startAvailability=1;
	char buf[2];
	char seatBuf[3], psgBuf[2];
	int i;
	int myIdentifier = 0;
	
	myIdentifier = GetMV(g_caIndex);
	SetMV(g_caIndex, myIdentifier +1);
	
	itoa(buf, 2, myIdentifier);
	
	while(1)
	{
		Acquire(signalAttendantsLock,0);
		
		Wait(signalAttendants, signalAttendantsLock,0);
		if(GetMV(attendantBroadcast) == 0) /*not Boradcast yet for psg in line*/
		{
			SetMV(attendantBroadcast, 1); /*now I Broadcast*/
			Release(signalAttendantsLock,0);
			Acquire(waitingForAttendantsLock,0);
			/*Acquire lock for the coach attendant line*/
			
			Acquire(coachAttendantLineLock[myIdentifier],0);
			/*start broadcast*/
			Broadcast(waitingForAttendants, waitingForAttendantsLock,0); 
			
			Release(waitingForAttendantsLock,0);
		}
		else{
			Release(signalAttendantsLock,0);
			Acquire(coachAttendantLineLock[myIdentifier],0);
		}
		
		SetMV(coachAttendantBusy[myIdentifier], 0);
		startAvailability=1;
		while (GetMV(passengerWaitingToBeSeated)>0)
		{
			startAvailability=0;
			/*Wait on the availability monitor for the first passenger to signal; the rest will form a line*/
			Wait(coachAttendantAvailable[myIdentifier], coachAttendantLineLock[myIdentifier],0);

			/*So since I'm this far the passenger has woken me up and is ready to have seat assigned
			  Generate random seat assignment and check that it is valid*/
			SetMV(seatAssignment[myIdentifier], RandomInt()%(3*MAXPASSENGERS-1));
			while(GetMV(seats[GetMV(seatAssignment[myIdentifier])]))
				SetMV(seatAssignment[myIdentifier], RandomInt()%(3*MAXPASSENGERS-1));
			/*Valid seat assignment now*/
			SetMV(seats[GetMV(seatAssignment[myIdentifier])], 1);
			itoa(seatBuf, 3, GetMV(seatAssignment[myIdentifier]));
			itoa(psgBuf, 2,  GetMV(g_seatingPsgNumber[myIdentifier]));
			PrintOut("Coach Attendant [",17);
			PrintOut(buf, 2);
			PrintOut("] of Train [0] gives seat number [",34);
			PrintOut(seatBuf, 3);
			PrintOut("] to Passenger [", 16 );
			PrintOut(psgBuf , 2);
			PrintOut("]\n", 2);
			/*If passenger is first class, wake up the porter to help with luggage*/
			if (GetMV(firstClass[GetMV(g_seatingPsgNumber[myIdentifier])]) == 1)
				SetMV(numNeedHelpWithLuggage, GetMV(numNeedHelpWithLuggage)+1);
			
			/*Copy over identifier for this coach attendant so that passenger can use*/

			/*Signal passenger that seat has been assigned*/
			Signal(coachAttendantAvailable[myIdentifier], coachAttendantLineLock[myIdentifier],0);
			/*Decrement number of passengers waiting to be seated*/
			SetMV(passengerWaitingToBeSeated, GetMV(passengerWaitingToBeSeated)-1);
			/*Make myself available for next passenger in wait queue*/
			if(GetMV(waitingToBeSatLineLength[myIdentifier])==0)	
				SetMV(coachAttendantBusy[myIdentifier], 0);
			/*Or signal those remaining on the line*/
			else
				Signal(coachAttendantLine[myIdentifier], coachAttendantLineLock[myIdentifier],0);
		}
		if(GetMV(numNeedHelpWithLuggage)>0){
			/*Exit the Coach Attendant monitor*/
			Release(coachAttendantLineLock[myIdentifier],0);
			Acquire(signalPortersLock,0);
			/*Attendant broadcasts to Porter*/
			Broadcast(signalPorters, signalPortersLock,0);
			Release(signalPortersLock,0);
		}
		else if (GetMV(passengerWaitingToBeSeated)<=0)
		{
			/*Exit the Coach Attendant monitor*/
			Release(coachAttendantLineLock[myIdentifier],0);
		}
		else
			Release(coachAttendantLineLock[myIdentifier],0);
	}
	
	Exit(0);
}
int myexp ( int count ) {
  int i, val=1;
  for (i=0; i<count; i++ ) {
    val = val * 10;
  }
  return val;
}

void itoa( char arr[], int size, int val ) {
  int i, max, dig, subval, loc;
  for (i=0; i<size; i++ ) {
    arr[i] = '\0';
  }

  for ( i=1; i<=10; i++ ) {
    if (( val / myexp(i) ) == 0 ) {
      max = i-1;
      break;
    }
  }

  subval = 0;
  loc = 0;
  for ( i=max; i>=0; i-- ) {
    dig = 48 + ((val-subval) / myexp(i));
    subval += (dig-48) * myexp(i);
    arr[loc] = dig;
    loc++;
  }

  return;
}